-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clang-doc] Extract Info into JSON values #138063
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang-tools-extra Author: Paul Kirth (ilovepi) ChangesSplit from #133161. This patch provides the implementation of a number The new helper functions extract the relevant information from the Co-authored-by: Peter Chou <[email protected]> Full diff: https://github.com/llvm/llvm-project/pull/138063.diff 1 Files Affected:
diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
index 593d5d1221f44..29392f8bf17b9 100644
--- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
+++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp
@@ -141,21 +141,272 @@ Error MustacheHTMLGenerator::generateDocs(
return Error::success();
}
+static json::Value
+extractValue(const Location &L,
+ std::optional<StringRef> RepositoryUrl = std::nullopt) {
+ Object Obj = Object();
+ // Should there be Start/End line numbers?
+ Obj.insert({"LineNumber", L.StartLineNumber});
+ Obj.insert({"Filename", L.Filename});
+
+ if (!L.IsFileInRootDir || !RepositoryUrl) {
+ return Obj;
+ }
+ SmallString<128> FileURL(*RepositoryUrl);
+ sys::path::append(FileURL, sys::path::Style::posix, L.Filename);
+ FileURL += "#" + std::to_string(L.StartLineNumber);
+ Obj.insert({"FileURL", FileURL});
+
+ return Obj;
+}
+
+static json::Value extractValue(const Reference &I,
+ StringRef CurrentDirectory) {
+ SmallString<64> Path = I.getRelativeFilePath(CurrentDirectory);
+ sys::path::append(Path, I.getFileBaseName() + ".html");
+ sys::path::native(Path, sys::path::Style::posix);
+ Object Obj = Object();
+ Obj.insert({"Link", Path});
+ Obj.insert({"Name", I.Name});
+ Obj.insert({"QualName", I.QualName});
+ Obj.insert({"ID", toHex(toStringRef(I.USR))});
+ return Obj;
+}
+
+static json::Value extractValue(const TypedefInfo &I) {
+ // Not Supported
+ return nullptr;
+}
+
+static json::Value extractValue(const CommentInfo &I) {
+ assert((I.Kind == "BlockCommandComment" || I.Kind == "FullComment" ||
+ I.Kind == "ParagraphComment" || I.Kind == "TextComment") &&
+ "Unknown Comment type in CommentInfo.");
+
+ Object Obj = Object();
+ json::Value Child = Object();
+
+ // TextComment has no children, so return it.
+ if (I.Kind == "TextComment") {
+ Obj.insert({"TextComment", I.Text});
+ return Obj;
+ }
+
+ // BlockCommandComment needs to generate a Command key.
+ if (I.Kind == "BlockCommandComment") {
+ Child.getAsObject()->insert({"Command", I.Name});
+ }
+
+ // Use the same handling for everything else.
+ // Only valid for:
+ // - BlockCommandComment
+ // - FullComment
+ // - ParagraphComment
+ json::Value ChildArr = Array();
+ auto &CARef = *ChildArr.getAsArray();
+ CARef.reserve(I.Children.size());
+ for (const auto &C : I.Children)
+ CARef.emplace_back(extractValue(*C));
+ Child.getAsObject()->insert({"Children", ChildArr});
+ Obj.insert({I.Kind, Child});
+
+ return Obj;
+}
+
+static void maybeInsertLocation(std::optional<Location> Loc,
+ const ClangDocContext &CDCtx, Object &Obj) {
+ if (!Loc)
+ return;
+ Location L = *Loc;
+ Obj.insert({"Location", extractValue(L, CDCtx.RepositoryUrl)});
+}
+
+static void extractDescriptionFromInfo(ArrayRef<CommentInfo> Descriptions,
+ json::Object &EnumValObj) {
+ if (Descriptions.empty())
+ return;
+ json::Value ArrDesc = Array();
+ json::Array &ADescRef = *ArrDesc.getAsArray();
+ for (const CommentInfo &Child : Descriptions)
+ ADescRef.emplace_back(extractValue(Child));
+ EnumValObj.insert({"EnumValueComments", ArrDesc});
+}
+
+static json::Value extractValue(const FunctionInfo &I, StringRef ParentInfoDir,
+ const ClangDocContext &CDCtx) {
+ Object Obj = Object();
+ Obj.insert({"Name", I.Name});
+ Obj.insert({"ID", toHex(toStringRef(I.USR))});
+ Obj.insert({"Access", getAccessSpelling(I.Access).str()});
+ Obj.insert({"ReturnType", extractValue(I.ReturnType.Type, ParentInfoDir)});
+
+ json::Value ParamArr = Array();
+ for (const auto Val : enumerate(I.Params)) {
+ json::Value V = Object();
+ auto &VRef = *V.getAsObject();
+ VRef.insert({"Name", Val.value().Name});
+ VRef.insert({"Type", Val.value().Type.Name});
+ VRef.insert({"End", Val.index() + 1 == I.Params.size()});
+ ParamArr.getAsArray()->emplace_back(V);
+ }
+ Obj.insert({"Params", ParamArr});
+
+ maybeInsertLocation(I.DefLoc, CDCtx, Obj);
+ return Obj;
+}
+
+static json::Value extractValue(const EnumInfo &I,
+ const ClangDocContext &CDCtx) {
+ Object Obj = Object();
+ std::string EnumType = I.Scoped ? "enum class " : "enum ";
+ EnumType += I.Name;
+ bool HasComment = std::any_of(
+ I.Members.begin(), I.Members.end(),
+ [](const EnumValueInfo &M) { return !M.Description.empty(); });
+ Obj.insert({"EnumName", EnumType});
+ Obj.insert({"HasComment", HasComment});
+ Obj.insert({"ID", toHex(toStringRef(I.USR))});
+ json::Value Arr = Array();
+ json::Array &ARef = *Arr.getAsArray();
+ for (const EnumValueInfo &M : I.Members) {
+ json::Value EnumValue = Object();
+ auto &EnumValObj = *EnumValue.getAsObject();
+ EnumValObj.insert({"Name", M.Name});
+ if (!M.ValueExpr.empty())
+ EnumValObj.insert({"ValueExpr", M.ValueExpr});
+ else
+ EnumValObj.insert({"Value", M.Value});
+
+ extractDescriptionFromInfo(M.Description, EnumValObj);
+ ARef.emplace_back(EnumValue);
+ }
+ Obj.insert({"EnumValues", Arr});
+
+ extractDescriptionFromInfo(I.Description, Obj);
+ maybeInsertLocation(I.DefLoc, CDCtx, Obj);
+
+ return Obj;
+}
+
+static void extractScopeChildren(const ScopeChildren &S, Object &Obj,
+ StringRef ParentInfoDir,
+ const ClangDocContext &CDCtx) {
+ json::Value ArrNamespace = Array();
+ for (const Reference &Child : S.Namespaces)
+ ArrNamespace.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
+
+ if (!ArrNamespace.getAsArray()->empty())
+ Obj.insert({"Namespace", Object{{"Links", ArrNamespace}}});
+
+ json::Value ArrRecord = Array();
+ for (const Reference &Child : S.Records)
+ ArrRecord.getAsArray()->emplace_back(extractValue(Child, ParentInfoDir));
+
+ if (!ArrRecord.getAsArray()->empty())
+ Obj.insert({"Record", Object{{"Links", ArrRecord}}});
+
+ json::Value ArrFunction = Array();
+ json::Value PublicFunction = Array();
+ json::Value ProtectedFunction = Array();
+ json::Value PrivateFunction = Array();
+
+ for (const FunctionInfo &Child : S.Functions) {
+ json::Value F = extractValue(Child, ParentInfoDir, CDCtx);
+ AccessSpecifier Access = Child.Access;
+ if (Access == AccessSpecifier::AS_public)
+ PublicFunction.getAsArray()->emplace_back(F);
+ else if (Access == AccessSpecifier::AS_protected)
+ ProtectedFunction.getAsArray()->emplace_back(F);
+ else
+ ArrFunction.getAsArray()->emplace_back(F);
+ }
+
+ if (!ArrFunction.getAsArray()->empty())
+ Obj.insert({"Function", Object{{"Obj", ArrFunction}}});
+
+ if (!PublicFunction.getAsArray()->empty())
+ Obj.insert({"PublicFunction", Object{{"Obj", PublicFunction}}});
+
+ if (!ProtectedFunction.getAsArray()->empty())
+ Obj.insert({"ProtectedFunction", Object{{"Obj", ProtectedFunction}}});
+
+ json::Value ArrEnum = Array();
+ auto &ArrEnumRef = *ArrEnum.getAsArray();
+ for (const EnumInfo &Child : S.Enums)
+ ArrEnumRef.emplace_back(extractValue(Child, CDCtx));
+
+ if (!ArrEnumRef.empty())
+ Obj.insert({"Enums", Object{{"Obj", ArrEnum}}});
+
+ json::Value ArrTypedefs = Array();
+ auto &ArrTypedefsRef = *ArrTypedefs.getAsArray();
+ for (const TypedefInfo &Child : S.Typedefs)
+ ArrTypedefsRef.emplace_back(extractValue(Child));
+
+ if (!ArrTypedefsRef.empty())
+ Obj.insert({"Typedefs", Object{{"Obj", ArrTypedefs}}});
+}
+
static json::Value extractValue(const NamespaceInfo &I,
const ClangDocContext &CDCtx) {
Object NamespaceValue = Object();
+ std::string InfoTitle = I.Name.empty() ? "Global Namespace"
+ : (Twine("namespace ") + I.Name).str();
+
+ StringRef BasePath = I.getRelativeFilePath("");
+ NamespaceValue.insert({"NamespaceTitle", InfoTitle});
+ NamespaceValue.insert({"NamespacePath", BasePath});
+
+ extractDescriptionFromInfo(I.Description, NamespaceValue);
+ extractScopeChildren(I.Children, NamespaceValue, BasePath, CDCtx);
return NamespaceValue;
}
static json::Value extractValue(const RecordInfo &I,
const ClangDocContext &CDCtx) {
Object RecordValue = Object();
+ extractDescriptionFromInfo(I.Description, RecordValue);
+ RecordValue.insert({"Name", I.Name});
+ RecordValue.insert({"FullName", I.FullName});
+ RecordValue.insert({"RecordType", getTagType(I.TagType)});
+
+ maybeInsertLocation(I.DefLoc, CDCtx, RecordValue);
+
+ StringRef BasePath = I.getRelativeFilePath("");
+ extractScopeChildren(I.Children, RecordValue, BasePath, CDCtx);
+ json::Value PublicMembers = Array();
+ json::Array &PubMemberRef = *PublicMembers.getAsArray();
+ json::Value ProtectedMembers = Array();
+ json::Array &ProtMemberRef = *ProtectedMembers.getAsArray();
+ json::Value PrivateMembers = Array();
+ json::Array &PrivMemberRef = *PrivateMembers.getAsArray();
+ for (const MemberTypeInfo &Member : I.Members) {
+ json::Value MemberValue = Object();
+ auto &MVRef = *MemberValue.getAsObject();
+ MVRef.insert({"Name", Member.Name});
+ MVRef.insert({"Type", Member.Type.Name});
+ extractDescriptionFromInfo(Member.Description, MVRef);
+
+ if (Member.Access == AccessSpecifier::AS_public)
+ PubMemberRef.emplace_back(MemberValue);
+ else if (Member.Access == AccessSpecifier::AS_protected)
+ ProtMemberRef.emplace_back(MemberValue);
+ else if (Member.Access == AccessSpecifier::AS_private)
+ ProtMemberRef.emplace_back(MemberValue);
+ }
+ if (!PubMemberRef.empty())
+ RecordValue.insert({"PublicMembers", Object{{"Obj", PublicMembers}}});
+ if (!ProtMemberRef.empty())
+ RecordValue.insert({"ProtectedMembers", Object{{"Obj", ProtectedMembers}}});
+ if (!PrivMemberRef.empty())
+ RecordValue.insert({"PrivateMembers", Object{{"Obj", PrivateMembers}}});
+
return RecordValue;
}
static void setupTemplateValue(const ClangDocContext &CDCtx, json::Value &V,
- Info *I) {}
-
+ Info *I) {
+}
Error MustacheHTMLGenerator::generateDocForInfo(Info *I, raw_ostream &OS,
const ClangDocContext &CDCtx) {
switch (I->IT) {
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
5af67bc
to
888f545
Compare
77bb241
to
516f2b2
Compare
888f545
to
e215c97
Compare
516f2b2
to
50755c0
Compare
e215c97
to
d832772
Compare
50755c0
to
1ef8e3c
Compare
e66d950
to
8a5872d
Compare
0ec149d
to
f8205f7
Compare
0e2e6ad
to
ac8c55e
Compare
f8205f7
to
1079b7d
Compare
0e6ab7d
to
c7f6fb8
Compare
6d311cf
to
fb0db52
Compare
c7f6fb8
to
fa76fb7
Compare
e918ff1
to
442fe2f
Compare
fa76fb7
to
d0754f4
Compare
442fe2f
to
3d87071
Compare
d0754f4
to
8e0b4fc
Compare
8e0b4fc
to
51bd30a
Compare
3d87071
to
7f91d87
Compare
51bd30a
to
c97f7af
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just array naming nits.
c97f7af
to
6880c2f
Compare
7f91d87
to
86dc2be
Compare
afa7c63
to
03f3e44
Compare
Split from #133161. This patch provides the implementation of a number of extractValue overloads used with the different types of Info. The new helper functions extract the relevant information from the different *Infos and inserts them into the correct fields of the JSON values that will be used with the specific Mustache templates, which will land separately. Co-authored-by: Peter Chou <[email protected]>
03f3e44
to
0c7122c
Compare
Split from #133161. This patch provides the implementation of a number
of extractValue overloads used with the different types of Info.
The new helper functions extract the relevant information from the
different *Infos and inserts them into the correct fields of the JSON
values that will be used with the specific Mustache templates, which
will land separately.
Co-authored-by: Peter Chou [email protected]